/**
  Copyright (c) [2024] [JiangNan]
  [go-tools] is licensed under Mulan PSL v2.
  You can use this software according to the terms and conditions of the Mulan PSL v2.
  You may obtain a copy of Mulan PSL v2 at:
           http://license.coscl.org.cn/MulanPSL2
  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
  See the Mulan PSL v2 for more details.
*/

/*
	基本类型切片相关操作
*/

package slices

import (
	"math/bits"
)

// IsEmpty 判断切片是否为空
func IsEmpty(array []string) bool {
	if len(array) == 0 {
		return true
	}
	for _, s := range array {
		if s != "" {
			return false
		}
	}
	return true
}

// RepeatIndex 提取切片内重复值的索引
func RepeatIndex[E comparable](array []E) map[E][]int {

	result := map[E][]int{}

	for i, e := range array {
		if _, ok := result[e]; ok {
			result[e] = append(result[e], i)
		} else {
			result[e] = []int{i}
		}
	}

	for key, value := range result {
		if len(value) == 1 {
			delete(result, key)
		}
	}

	return result
}

// Filter 切片过滤
func Filter[T comparable](slice []T, condition func(T) bool) ([]T, []int) {
	var filtered []T
	var indexes []int
	for index, item := range slice {
		if condition(item) {
			filtered = append(filtered, item)
			indexes = append(indexes, index)
		}
	}
	return filtered, indexes
}

// SliceToAny 将切片类型转换为Any
func SliceToAny[T comparable](slice []T) []any {
	var anySlice []any
	for _, item := range slice {
		anySlice = append(anySlice, item)
	}
	return anySlice
}

// CreateSlice 使用给定值创建空切片
func CreateSlice[E any](v E, l int) []E {
	var values []E
	for i := 0; i < l; i++ {
		values = append(values, v)
	}
	return values
}

// Range 生成序列切片
func Range(start, stop, step int) []int {
	var x []int
	for i := start; i < stop; i += step {
		x = append(x, i)
	}
	return x
}

// Overlap 判断两个切片里的重复元素
func Overlap[T comparable](s1, s2 []T) []T {
	var overlap []T
	for _, t := range s1 {
		if Contains(s2, t) {
			overlap = append(overlap, t)
		}
	}
	return overlap
}

// Equal 判断两个切片是否相等
func Equal[S ~[]E, E comparable](s1, s2 S) bool {
	if len(s1) != len(s2) {
		return false
	}
	for i := range s1 {
		if s1[i] != s2[i] {
			return false
		}
	}
	return true
}

// EqualFunc 自定义函数判断两个切片是否相等
func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
	if len(s1) != len(s2) {
		return false
	}
	for i, v1 := range s1 {
		v2 := s2[i]
		if !eq(v1, v2) {
			return false
		}
	}
	return true
}

// Index 返回给定元素第一次出现的索引，如果不存在返回-1
func Index[S ~[]E, E comparable](s S, v E) int {
	for i := range s {
		if v == s[i] {
			return i
		}
	}
	return -1
}

// IndexFunc 返回满足 f（s[i]） 的第一个索引 i， 如果没有，则为 -1。
func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
	for i := range s {
		if f(s[i]) {
			return i
		}
	}
	return -1
}

// Contains 判断切片是否包含元素
func Contains[S ~[]E, E comparable](s S, v E) bool {
	return Index(s, v) >= 0
}

// ContainsFunc 报告是否至少有一个 S 的元素 e 满足 f（e）。
func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
	return IndexFunc(s, f) >= 0
}

// Insert 在切片的指定索引处开始插入元素
func Insert[S ~[]E, E any](s S, i int, v ...E) S {
	_ = s[i:] // bounds check
	if i >= len(s) {
		i = len(s)
	} else if i < 0 {
		i = 0
	}
	newS := make(S, len(v)+1)
	newS = append(newS, s[:i]...)
	newS = append(newS, v...)
	newS = append(newS, s[i:]...)
	return newS
}

// Delete 删除指定索引范围内的元素
func Delete[S ~[]E, E any](s S, i, j int) S {
	_ = s[i:j:len(s)] // bounds check

	if i == j {
		return s
	}
	s = append(s[:i], s[j:]...)
	return s
}

// Clone 复制切片
func Clone[S ~[]E, E any](s S) S {
	// The s[:0:0] preserves nil in case it matters.
	return append(s[:0:0], s...)
}

// Grow 切片扩容
func Grow[S ~[]E, E any](s S, n int) S {
	if n < 0 {
		panic("cannot be negative")
	}
	if n -= cap(s) - len(s); n > 0 {
		s = append(s[:cap(s)], make([]E, n)...)[:len(s)]
	}
	return s
}

// Clip 从切片中删除未使用的容量，返回 s[：len（s）：len（s）]。
func Clip[S ~[]E, E any](s S) S {
	return s[:len(s):len(s)]
}

// Reverse 切片倒叙
func Reverse[S ~[]E, E any](s S) {
	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
		s[i], s[j] = s[j], s[i]
	}
}

// Concat 返回一个连接传入切片的新切片。
func Concat[S ~[]E, E any](slices ...S) S {
	size := 0
	for _, s := range slices {
		size += len(s)
		if size < 0 {
			panic("len out of range")
		}
	}
	newSlice := Grow[S](nil, size)
	for _, s := range slices {
		newSlice = append(newSlice, s...)
	}
	return newSlice
}

// Repeat 返回一个新切片，该切片将提供的切片重复给定次数。
func Repeat[S ~[]E, E any](x S, count int) S {
	if count < 0 {
		panic("cannot be negative")
	}

	const maxInt = ^uint(0) >> 1
	if hi, lo := bits.Mul(uint(len(x)), uint(count)); hi > 0 || lo > maxInt {
		panic("the result of (len(x) * count) overflows")
	}

	newslice := make(S, len(x)*count)
	n := copy(newslice, x)
	for n < len(newslice) {
		n += copy(newslice[n:], newslice[:n])
	}
	return newslice
}
